package cn.boot.asyncmy.service.impl;

import cn.boot.asyncmy.dao.MemberRepository;
import cn.boot.asyncmy.entity.Member;
import cn.boot.asyncmy.service.AsyncService;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.exception.ConstraintViolationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

@Service
public class AsyncServiceImpl implements AsyncService {
    private static Log logger = LogFactory.getLog(AsyncServiceImpl.class);
    @Autowired
    private MemberServiceImpl memberService;
    @Autowired
    private MemberRepository memberRepository;


    //★★注意★★：一般滴，事务的异常是在提交时抛出的，所以要在action层中捕获，service层是无法捕获的
    //https://www.iteye.com/blog/liuyunlong1229-2179346 https://segmentfault.com/q/1010000007963905/a-1020000007963973
    //所以 要用saveAndFlush方法， 或者把此方法移至action层
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class, noRollbackFor = ConstraintViolationException.class)
    public String writeCode3(String fileName) {
        logger.info("线程-" + Thread.currentThread().getId() + "在导入-" + fileName);
        File file = new File(fileName);
        List<String> list = null;
        try {
            list = FileUtils.readLines(file);
        } catch (IOException e) {
            e.printStackTrace();
        }
        int count = 0;
        for (String string : list) {
            String[] parmas = string.split("，");
            Member vo = new Member();
//          vo.setDate(DateUtils.parseDate(parmas[0], "yyyy-MM-dd"));//date == null   date = new Date();
            vo.setName(parmas[1]);
            vo.setPlace(parmas[2]);
            vo.setSex(StringUtils.isBlank(parmas[3]) ? 0 : Integer.parseInt(parmas[3]));
            vo.setIdCard(parmas[4]);
            try {
                memberRepository.saveAndFlush(vo);
            } catch (DataIntegrityViolationException e) {
                logger.info("--->e1-" +  e.getMessage());
                if(e.getCause()!=null && (e.getCause() instanceof ConstraintViolationException)){
//                    throw (ConstraintViolationException)e.getCause();
//                    continue;
                }else{
                    logger.info("--->e2-" +  e.getMessage());

                }
            } catch (Exception e) {
                logger.info("--->e3-" +  e.getMessage());
            }
            count++;
            logger.info("--->完成第-" + count + "-条导入");
        }
        return "导入完成-" + fileName;
    }

    @Override
//    @Async("asyncServiceExecutor")
    //★★注意★★：if这个@Transactional加在memberService.saveMember(vo)方法上的话，就不会批量回滚了！ 放在此方法上或者此方法所属的类上，或者采取writeCode2方法
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public String writeCode1(String fileName) { // java.lang.ArrayIndexOutOfBoundsException
        logger.info("线程-" + Thread.currentThread().getId() + "在导入-" + fileName);
        File file = new File(fileName);
        List<String> list = null;
        try {
            list = FileUtils.readLines(file);
        } catch (IOException e) {
            e.printStackTrace();
        }
        int count = 0;
        for (String string : list) {
            String[] parmas = string.split("，");
            Member vo = new Member();
//          vo.setDate(DateUtils.parseDate(parmas[0], "yyyy-MM-dd"));
            vo.setName(parmas[1]);
            vo.setPlace(parmas[2]);
            vo.setSex(StringUtils.isBlank(parmas[3]) ? 0 : Integer.parseInt(parmas[3]));
            vo.setIdCard(parmas[4]);
//            memberService.saveMember(vo);     //当前类上的@Transactional +  .saveMember(vo)上的无@Transactional            可以批量回顾
            memberRepository.save(vo);          //当前类上的@Transactional +  .save(vo)            可以批量回顾
//            memberRepository.saveAndFlush(vo);//当前类上的@Transactional +  .saveAndFlush(vo)  不可以批量回顾 (导入数据时 过滤重复数据又用)
            //save不会立刻提交到数据库，flush则立刻提交生效，save可能只是修改在内存中的
            count++;
            logger.info("--->完成第-" + count + "-条导入");
        }
        return "导入完成-" + fileName;
    }



    //略10
    @Override
    public String writeCode2(String fileName) {
        logger.info("线程-" + Thread.currentThread().getId() + "在导入-" + fileName);
        File file = new File(fileName);
        List<String> list = null;
        try {
            list = FileUtils.readLines(file);
        } catch (IOException e) {
            e.printStackTrace();
        }
        List<Member> members = new ArrayList<>();
        for (String string : list) {
            String[] parmas = string.split("，");
            Member vo = new Member();
//          vo.setDate(DateUtils.parseDate(parmas[0], "yyyy-MM-dd"));
            vo.setName(parmas[1]);
            vo.setPlace(parmas[2]);
            vo.setSex(StringUtils.isBlank(parmas[3]) ? 0 : Integer.parseInt(parmas[3]));
            vo.setIdCard(StringUtils.isBlank(parmas[4]) ? null : parmas[4]);
            members.add(vo);
        }
        memberService.saveMemberList(members);
        return "导入完成-" + fileName;
    }

}
